using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using JGSY.CMS.LowCode.Platform.Application.DTOs;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;

namespace JGSY.CMS.LowCode.Platform.Infrastructure.Middleware
{
    /// <summary>
    /// 全局异常处理中间件
    /// </summary>
    public class ExceptionHandlingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<ExceptionHandlingMiddleware> _logger;

        public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "An unhandled exception occurred: {Message}", ex.Message);
                
                // 记录异常日志到数据库
                await LogExceptionToDatabaseAsync(context, ex);
                
                await HandleExceptionAsync(context, ex);
            }
        }

        private async Task LogExceptionToDatabaseAsync(HttpContext context, Exception exception)
        {
            try
            {
                // 基本的控制台日志记录
                _logger.LogCritical(exception, 
                    "Critical exception occurred. TraceId: {TraceId}, UserId: {UserId}, Path: {Path}, Method: {Method}, IP: {IpAddress}",
                    context.TraceIdentifier,
                    GetUserIdFromContext(context),
                    context.Request.Path,
                    context.Request.Method,
                    GetClientIpAddress(context));

                // 数据库异常日志记录（现在可以启用）
                var exceptionLogService = context.RequestServices.GetService<IExceptionLogAppService>();
                if (exceptionLogService != null)
                {
                    var additionalData = new Dictionary<string, object>
                    {
                        ["IpAddress"] = GetClientIpAddress(context),
                        ["UserAgent"] = context.Request.Headers.UserAgent.ToString(),
                        ["RequestHeaders"] = context.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToString()),
                        ["QueryString"] = context.Request.QueryString.ToString(),
                        ["ResponseStatusCode"] = context.Response.StatusCode
                    };

                    await exceptionLogService.LogExceptionAsync(
                        exception,
                        traceId: context.TraceIdentifier,
                        correlationId: context.Request.Headers.TryGetValue("X-Correlation-ID", out var corrValues) ? 
                            corrValues.FirstOrDefault() : null,
                        tenantId: GetTenantIdFromContext(context),
                        userId: GetUserIdFromContext(context),
                        requestPath: context.Request.Path,
                        httpMethod: context.Request.Method,
                        additionalData: additionalData);
                }
            }
            catch (Exception logEx)
            {
                // 记录日志失败不应影响异常处理流程
                _logger.LogError(logEx, "Failed to log exception to database");
            }
        }

        private string? GetTenantIdFromContext(HttpContext context)
        {
            // 尝试从多个位置获取租户ID
            return context.Request.Headers.TryGetValue("X-Tenant-ID", out var tenantValues) ? 
                tenantValues.FirstOrDefault() :
                context.User?.FindFirst("tenant_id")?.Value;
        }

        private string? GetUserIdFromContext(HttpContext context)
        {
            // 尝试从用户声明中获取用户ID
            return context.User?.FindFirst("sub")?.Value ?? 
                context.User?.FindFirst("user_id")?.Value ??
                context.User?.Identity?.Name;
        }

        private string? GetUserNameFromContext(HttpContext context)
        {
            return context.User?.FindFirst("name")?.Value ?? 
                context.User?.FindFirst("username")?.Value;
        }

        private string GetClientIpAddress(HttpContext context)
        {
            // 尝试从多个位置获取客户端IP地址
            var xForwardedFor = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (!string.IsNullOrEmpty(xForwardedFor))
            {
                var ips = xForwardedFor.Split(',');
                return ips[0].Trim();
            }

            var xRealIp = context.Request.Headers["X-Real-IP"].FirstOrDefault();
            if (!string.IsNullOrEmpty(xRealIp))
            {
                return xRealIp;
            }

            return context.Connection.RemoteIpAddress?.ToString() ?? "Unknown";
        }

        private async Task<string> GetRequestBodyAsync(HttpContext context)
        {
            try
            {
                if (context.Request.ContentLength > 0 && context.Request.ContentLength < 10240) // 限制10KB
                {
                    context.Request.EnableBuffering();
                    context.Request.Body.Position = 0;
                    using var reader = new StreamReader(context.Request.Body);
                    var body = await reader.ReadToEndAsync();
                    context.Request.Body.Position = 0;
                    return body;
                }
            }
            catch
            {
                // 读取请求体失败时忽略
            }
            return string.Empty;
        }

        private async Task HandleExceptionAsync(HttpContext context, Exception exception)
        {
            context.Response.ContentType = "application/json";
            
            var response = new ApiErrorResponse
            {
                Message = "An error occurred while processing your request.",
                Details = exception.Message
            };

            switch (exception)
            {
                case ArgumentNullException:
                case ArgumentException:
                    context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                    response.Message = "Invalid request parameters.";
                    response.Code = "INVALID_PARAMETERS";
                    break;

                case UnauthorizedAccessException:
                    context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                    response.Message = "Access denied.";
                    response.Code = "ACCESS_DENIED";
                    break;

                case InvalidOperationException:
                    context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
                    response.Message = exception.Message;
                    response.Code = "INVALID_OPERATION";
                    break;

                case NotImplementedException:
                    context.Response.StatusCode = (int)HttpStatusCode.NotImplemented;
                    response.Message = "This feature is not implemented yet.";
                    response.Code = "NOT_IMPLEMENTED";
                    break;

                case TimeoutException:
                    context.Response.StatusCode = (int)HttpStatusCode.RequestTimeout;
                    response.Message = "The request timed out.";
                    response.Code = "TIMEOUT";
                    break;

                default:
                    context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                    response.Message = "An internal server error occurred.";
                    response.Code = "INTERNAL_ERROR";
                    break;
            }

            // 在开发环境中显示详细错误信息
            if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
            {
                response.Details = exception.ToString();
                response.StackTrace = exception.StackTrace;
            }
            else
            {
                // 生产环境中隐藏敏感信息
                response.Details = null;
                response.StackTrace = null;
            }

            var jsonResponse = JsonSerializer.Serialize(response, new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                WriteIndented = true
            });

            await context.Response.WriteAsync(jsonResponse);
        }
    }

    /// <summary>
    /// API错误响应
    /// </summary>
    public class ApiErrorResponse
    {
        /// <summary>
        /// 错误消息
        /// </summary>
        public string Message { get; set; } = string.Empty;

        /// <summary>
        /// 错误代码
        /// </summary>
        public string? Code { get; set; }

        /// <summary>
        /// 错误详情
        /// </summary>
        public string? Details { get; set; }

        /// <summary>
        /// 堆栈跟踪（仅开发环境）
        /// </summary>
        public string? StackTrace { get; set; }

        /// <summary>
        /// 时间戳
        /// </summary>
        public DateTime Timestamp { get; set; } = DateTime.UtcNow;

        /// <summary>
        /// 请求ID
        /// </summary>
        public string? RequestId { get; set; }
    }
}
